package com.yyq.sos.dao;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import org.hibernate.EntityMode;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.persister.entity.SingleTableEntityPersister;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.yyq.sos.constants.Constants;
import com.yyq.sos.logs.LoggerProxy;
import com.yyq.sos.util.LogsUtil;
import com.yyq.sos.util.ObjectUtil;
import com.yyq.sos.util.SequencesUtil;


/**
 * ��Dao�ӿ�ʵ���࣬�����װ�˶���ݵĴ󲿷ֵĲ����?�����Ҫ�������
 * )չ������Ҫ����ģ�鼶��������н��У���Ҫ�ڱ�������)չ����
 * @author Administrator
 *
 */
public class BaseDaoImplCurrentSession implements BaseDao
{

	/**
	 * ע��sessionFactory
	 * @param sessionFactory
	 */
	@Autowired
	private SessionFactory sessionFactory;
	
	protected Session getSession() {
		return sessionFactory.getCurrentSession();
	}
	/**
	 * ���һ������¼����ݿ�
	 * @param obj Object :��Ҫ����Ķ���ӳ��һ���¼
	 * @return long :������ɵ��������
	 */
	public Serializable add(Object obj) {
		Serializable[] ids = this.add(new Object[]{obj});
		Serializable id = null;
		if(ids!=null)
			id = ids[0];
		return id;
	}

	public Serializable buildPrimaryKey(Object obj){
		Serializable value = null;
		Class cls = obj.getClass();
		ClassMetadata meta = this.getSessionFactory().getClassMetadata(cls);
		String name = meta.getIdentifierPropertyName();
		value = (Serializable)ObjectUtil.getValue(obj, ObjectUtil.getGetter(name), new Class[]{}, new Object[]{});
		if(value==null){
			Class type = ObjectUtil.getField(cls, name).getType();
			Long pkId = SequencesUtil.getInstance().getNextPk(cls);
			value = pkId;
			if(type.equals(Long.class)){
				ObjectUtil.setValue(obj, ObjectUtil.getSetter(name), new Class[]{type}, new Object[]{pkId});
			}else if(type.equals(Integer.class)){
				ObjectUtil.setValue(obj, ObjectUtil.getSetter(name), new Class[]{type}, new Object[]{new Integer(pkId.intValue())});
			}else{
				ObjectUtil.setValue(obj, ObjectUtil.getSetter(name), new Class[]{type}, new Object[]{new Short(pkId.shortValue())});
			}
		}
		return value;
	}
	

	/**
	 * ������ 
	 */
	public Serializable[] add(Object[] objs) {
		Serializable[] ids = null;
		String content = null;
		List list = new ArrayList();
		if(objs!=null && objs.length>0){
			Class cls = objs[0].getClass();
			ids = new Serializable[objs.length];
			Transaction tx = null;
			Session session = this.getSession();
			try{
				for(int i=0,len=objs.length; i<len; ++i){
					ids[i] = this.buildPrimaryKey(objs[i]);
//System.out.println("ids------------------->"+ids[i]+"   cardTypeRelationid===>"+((CardTypeRelation)objs[i]).getRelId());
					list.add(objs[i]);
				}
				tx = session.beginTransaction();
				for(int i=0, len = objs.length; i<len; ++i) {
					ids[i] =  session.save(objs[i]);
					if(i%1000==0){
						session.flush();
						session.clear();
					}
				}
				tx.commit();
				content = LogsUtil.getBatchSaveString(objs);
			}catch(Exception ex){
				try {
					tx.rollback();
				} catch (Exception e) {
					e.printStackTrace();
				}
				ex.printStackTrace();
				content = this.getExceptionResult(ex);
				ids = null;
			}finally{
				LoggerProxy.getProxy().log(getTableName(cls),
						Constants.LOG_WRITE,ids!=null?"success":"fail",content);
			}
		}
		return ids;
	}
	
	private boolean delete(Class cls,String hql){
		boolean bool =false; 
		Transaction tx =null;
		String content = null;
		Session session = this.getSession();
		try{
			tx = session.beginTransaction();
			List list = session.createQuery(hql.replaceAll("delete", "from ")).list();
			session.createQuery(hql).executeUpdate();
			tx.commit();
			bool = true;
			content = LogsUtil.getBatchDeleteString(list.toArray());
		}
		catch(Exception ex){
			tx.rollback();
			content = this.getExceptionResult(ex);
		}
		finally{
			LoggerProxy.getProxy().log(getTableName(cls),
					Constants.LOG_DELETE,bool?"success":"fail",content);
		}
		return bool;
	}
	
	/**
	 * ɾ��һ���¼
	 */
	public boolean delete(Object obj){
		String hql = this.getDeleteHql(obj, null,null);
		return this.delete(obj.getClass(), hql);
		
	}
	
	private String getDeleteHql(Object obj,Class cls,java.io.Serializable[] ids){
		if(obj!=null)
			cls = obj.getClass();
		ClassMetadata meta = this.getSessionFactory().getClassMetadata(cls);
		String name = meta.getIdentifierPropertyName();
		if(ids == null){
			ids = new java.io.Serializable[1];
			ids[0] = (Serializable)ObjectUtil.getValue(obj, ObjectUtil.getGetter(name), new Class[]{}, new Object[]{});
		}
		Class type = ObjectUtil.getField(cls, name).getType();
		StringBuffer buf = new StringBuffer("delete "+cls.getName()+" where ");
		for(int i=0,len = ids.length; i<len; ++i){
			if(i!=0)
				buf.append(" or ");
			if(type.equals(String.class)){
				buf.append(name);
				buf.append("='");
				buf.append(ids[i]);
				buf.append("'");
			}
			else{
				buf.append(name);
				buf.append("=");
				buf.append(ids[i]);
			}
		}
		return buf.toString();
	}
	
	
	/**
	 * ɾ��һ���¼
	 */
	public boolean delete(Class cls, long id){
		return this.delete(cls, this.getDeleteHql(null, cls, new java.io.Serializable[]{new Long(id)}));
	}
	
	/**
	 * ɾ��һ���¼
	 */
	public boolean delete(Class cls, Serializable id){
		return this.delete(cls, this.getDeleteHql(null, cls, new Serializable[]{id}));
	}
	
	/**
	 * ɾ������¼
	 */
	public boolean delete(Class cls, long[] ids){
		java.io.Serializable[] id = new Serializable[ids.length];
		for(int i=0, len=ids.length; i<len; ++i)
			id[i] = new Long(ids[i]);
		return this.delete(cls, this.getDeleteHql(null, cls, id));
	}
	
	/**
	 * ɾ������¼
	 */
	public boolean delete(Class cls, Serializable[] ids)
	{
		return this.delete(cls, this.getDeleteHql(null, cls, ids));
	}
	
	private String getExceptionResult(Exception ex){
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		ex.printStackTrace(new PrintStream(baos));
		System.out.println("-------------------------   Dao��������쳣        ------------->");
		return baos.toString();
	}
	
	/**
	 * ���sqlɾ���¼
	 */
	public boolean delete(String sql)
	{
		Transaction tx =null;
		boolean bool =false;
		List list = null;
		String content = "";
		Session session = null;
		try{
			String regex="";
			session = this.getSession();
			if(sql.toLowerCase().indexOf("from")<0)
				regex=" from ";
			String hql = sql.replaceAll("delete", regex);
			tx = session.beginTransaction();
			list = session.createQuery(hql).list();
			session.createQuery(sql).executeUpdate();
			tx.commit();
			bool = true;
			content = LogsUtil.getBatchDeleteString(list.toArray());
		}catch(Exception ex){
			tx.rollback();
			content = getExceptionResult(ex);
		}finally{
			if(list!=null && list.size()>0){
				Class cls = list.get(0).getClass();
				LoggerProxy.getProxy().log(getTableName(cls),
						Constants.LOG_DELETE,bool?"success":"fail",content);
			}
		}
		return bool;
	}

	
	/**
	 * ���������һ���¼
	 */
	public Object findByPk(Class cls, Serializable id)
	{
		Object obj = null;
		Session session = null;
		try{
			session = getSession();
			obj = session.get(cls, id);			
		}finally{
		}
		return obj;
	}
	
	/**
	 * ���������һ���¼
	 */
	public Object findByPk(Class cls, long id)
	{
		Object obj = null;
		Session session = null;
		try{
			session = getSession();
			obj = session.get(cls, Long.valueOf(id));
		}finally{
		}
		return obj;
	}
	
	/**
	 * ���sql����һ���¼
	 */
	public Object findByPk(String sql)
	{
		Object obj = null;
		Session session = null;
		try{
			session = getSession();
			List  list= session.createQuery(sql).list();
			if(list!=null && list.size()!=0)
				obj = list.get(0);
		}finally{
		}
		return obj;
	}

	/**
	 * ��ѯȫ����¼
	 */
	public List list(Class cls)
	{
		List list = null;
		String sql = "from "+cls.getName()+" obj ";
		Session session = null;
		try{
			session = getSession();
			if(ObjectUtil.getField(cls, "stsDate")!=null)
				sql += " where obj.sts='ACTV' or obj.sts='WAST'";
			list= session.createCriteria(cls).list();
		}finally{
		}
		return list;
	}
	
	/**
	 * ��ѯȫ����¼
	 */
	public List list(String sql)
	{
		List list = null;
		Session session = null;
		try{
			session = getSession();
			list= session.createQuery(sql).list();
		}finally{
		}
		return list;
	}

	/**
	 * ��ѯĳҳ��¼
	 * @param page ÿҳ��¼��
	 * @param size ��ǰҳ��
	 */
	public List listPage(Class cls, int page, int size)
	{
		List list = null;
		Session session = null;
		try{
			session = getSession();
			String sql = this.getQueryHql(cls);
			Query query = session.createQuery(sql);
			query.setFirstResult((page-1)*size);
			query.setMaxResults(size);
			list = query.list();
		}finally{
		}
		return list;
	}
	
	private String getQueryHql(Class cls){
		ClassMetadata meta = this.getSessionFactory().getClassMetadata(cls);
		String[] fields = meta.getPropertyNames();
		String sql="from "+cls.getName();
		boolean bool = false;
		for(int i=0; i<fields.length; ++i){
			if(fields[i].toUpperCase().equals("STS")){
				bool = true;
				sql += " order by sts asc";
			}
		}
		for(int i=0; i<fields.length; ++i){
			if(fields[i].toUpperCase().equals("STSDATE")){
				if(bool)
					sql += ",stsDate desc ";
				else
					sql += " order by stsDate desc ";
			}
			if(fields[i].toUpperCase().equals("STSTIME")){
				if(bool)
					sql += ",stsTime desc ";
				else
					sql += " order by stsTime desc ";
			}
		}
		return sql;
	}
	
	/**
	 * ��ѯĳҳ��¼
	 * @param page ÿҳ��¼��
	 * @param size ��ǰҳ��
	 */
	public List listPage(String sql, int page, int size)
	{
		List list = null;
		Session session = null;
		try{
			session = getSession();
			Query query = session.createQuery(sql);
			query.setMaxResults(size);
			query.setFirstResult((page-1)*size);
			list = query.list();
		}finally{
		}
		return list;
	}
	
	/**
	 * �ۺϲ�ѯ����
	 */
	public List search(String sql)
	{
		List list = null;
		Session session = null;
		try{
			session = getSession();
			list= session.createQuery(sql).list();
		}catch(Exception ex){
			ex.printStackTrace();
		}finally{
		}
		return list;
	}
	
	/**
	 * �ۺϲ�ѯ���������з�ҳ����
	 */
	public List search(String sql,int page,int size)
	{
		List list = null;
		Session session = null;
		try{
			session = getSession();
			Query query = session.createQuery(sql);
			query.setMaxResults(size);
			query.setFirstResult((page-1)*size);
			list = query.list();
		}finally{
		}
		return list;
	}
	
	/*
	 * �޸�һ���¼
	 */
	public boolean update(Object obj)
	{
		Transaction tx =null;
		boolean bool = false;
		String content = null;
		Object beforeVo = null;
		Object vo = null;
		Session session = getSession();
		try{
			tx = session.beginTransaction();
			Class cls = obj.getClass();
			ClassMetadata cmd = session.getSessionFactory().getClassMetadata(cls);
			String pkId = cmd.getIdentifierPropertyName();
			Serializable id = cmd.getIdentifier(obj, EntityMode.POJO);
			vo = session.get(obj.getClass(), id);
			beforeVo = ObjectUtil.cloneObject(vo);//this.processUpdateObject(vo);
			
			Method[] method = obj.getClass().getDeclaredMethods();
			for(int i=0;i<method.length; ++i){
				Method m = method[i];
				if(m.getName().startsWith("get")){
					Object value = m.invoke(obj, null);
					if(value!=null){
						try{
							Method voM = null;
							if(value.getClass().getName().indexOf("Timestamp")>0 || value.getClass().getName().indexOf("Time")>0 ||value.getClass().getName().indexOf("Date")>0)
								voM = vo.getClass().getMethod("set"+m.getName().substring(3), new Class[]{Date.class});
							else
								voM = vo.getClass().getMethod("set"+m.getName().substring(3), new Class[]{value.getClass()});
							voM.invoke(vo, new Object[]{value});
						}catch(Exception e){
							e.printStackTrace();
						}
					}
				}
			}
			session.update(vo);
			tx.commit();
			bool = true;
			content = LogsUtil.getUpdateString(beforeVo, vo);
		}catch(Exception ex){
			tx.rollback();
			content = this.getExceptionResult(ex);
		}finally{
			LoggerProxy.getProxy().log(getTableName(obj.getClass()),
						Constants.LOG_UPDATE,bool?"success":"fail",content);
		}
		return bool;
	}
	
	/**
	 * �޸�һ���¼�����sql
	 */
	public boolean update(String sql)
	{
		Transaction tx =null;
		boolean bool = false;
		Session session = null;
		try
		{
			session = getSession();
			tx = session.beginTransaction();
			session.createQuery(sql).executeUpdate();
			tx.commit();
			bool = true;
		}
		catch (Exception e){
			e.printStackTrace();
			tx.rollback();
		}finally{
		}
		return bool;
	}
	
	
	/**
	 * ������
	 */
	public boolean update(Object[] objs)
	{
		boolean bool = false;
		Transaction tx = null;
		Session session = null;
		try{
			session = getSession();
			tx = session.beginTransaction();
			for(int i=0; i<objs.length; ++i)
			{
				session.saveOrUpdate(objs[i]);
				if(i%100==0){
					session.flush();
					session.clear();
				}
			}
			tx.commit();
			bool = true;
		}catch(Exception ex){
			ex.printStackTrace();
			tx.rollback();
		}
		finally{
		}
		return bool;
	}
	
	/**
	 * ��ѯ��¼��
	 */
	public long count(Class cls)
	{
		long count = 0;
		Session session = null;
		try{
			session = getSession();
			Query query = session.createQuery("select count(*) from "+cls.getName()); 
			count = ((Long)(query.list().get(0))).intValue();
		}finally{
		}
		return count;
	}
	
	/**
	 * ��ѯ��¼��
	 */
	public long count(String sql)
	{
		long count = 0;
		Session session = null;
		try{
			int index = sql.toLowerCase().indexOf("from ");
			if(index>-1)
			{
				sql = sql.substring(index);
			}
			//�����ѯ��¼���¼��ʱȥ��order by �Ӿ�
			if (sql.toLowerCase().matches(".*order\\s+by.*")) {
				index=-1;
		    	index = sql.toLowerCase().indexOf("order");
		    	if (index >1) {
		    		sql = sql.substring(0, index);
		    	}
			}
			/*index = sql.toLowerCase().indexOf("order by");
			if(index>1)
			{
				sql = sql.substring(0, index);
			}*/
			session = getSession();
			Query query = session.createQuery("select count(*) "+sql); 
			count = ((Long)(query.list().get(0))).intValue();
		}finally{
		}
		return count;
	}
	
	/**
	 * ���sql�ж�ĳ���¼�Ƿ����
	 */
	public boolean exist(String sql)
	{
		boolean bool = false;
		Session session = null;
		try{
			session = getSession();
			Query query = session.createQuery(sql); 
			if(query.list().size()>0)
				bool = true;
		}catch(Exception ex){
			ex.printStackTrace();
		}finally{
		}
		return bool;
	}
	
	/**
	 * ���ID�ж�ĳ���¼�Ƿ����
	 */
	public boolean exist(Class cls,java.io.Serializable id)
	{
		boolean bool = false;
		Session session = null;
		try{
			session = getSession();
			Object obj = session.get(cls, id); 
			if(obj != null)
				bool = true;
		}catch(Exception ex){
			ex.printStackTrace();
		}finally{
		}
		return bool;
	}
	
	/**
	 * ȡ��ĳ���ֶε����ֵ
	 */
	public Object max(Class cls, String fieldName,String where) {
		Object value = null;
		Session session = null;
		try{
			String sql = "select max("+fieldName+") from "+cls.getName();
			if(where!=null && !where.trim().equals(""))
				sql += " where "+where;
			session = getSession();
			Query query = session.createQuery(sql);
			List list = query.list();
			if(list!=null && list.size()>0)
				value = list.get(0);
		}catch(Exception ex){
			ex.printStackTrace();
		}finally{
		}
		return value;
	}
	
	/**
	 * �޸�һ���¼����� sql
	 */
	public boolean execSql(String sql)
	{
		Transaction tx =null;
		boolean bool = false;
		Session session = null;
		try
		{
			session = getSession();
			tx = session.beginTransaction();
			Connection conn = session.connection();
			conn.prepareStatement(sql).executeUpdate();
			tx.commit();
			conn.close();
			bool = true;
		}
		catch (SQLException e)
		{
			e.printStackTrace();
			tx.rollback();
		}finally{
		}
		return bool;
	}

	public List listSql(String sql, int page, int size) {
		List list =null;
		Session session = getSession();
		try
		{
			SQLQuery query = session.createSQLQuery(sql);
			query.setFirstResult((page-1)*size);
			query.setMaxResults(size);
			list = query.list();
		}
		catch (Exception e){
			e.printStackTrace();
		}finally{
		}
		return list;
	}

	public List listSql(String sql) {
		List list =null;
		Session session = getSession();
		try
		{
			SQLQuery query = session.createSQLQuery(sql);
			list = query.list();
		}
		catch (Exception e){
			e.printStackTrace();
		}finally{
		}
		return list;
	}
	
	/**
	 * ��֤��Ч��
	 * @param effDate
	 * @param expDate
	 * @return
	 */
	public boolean validDateAvai(Class cls,String valueCondition,String effDate,String expDate){
		boolean bool = true;
		String sql = "from "+cls.getName()+" obj where ((obj.effDate <= '"+effDate+"' and obj.expDate>='"+effDate+"') or " +
				"(obj.effDate <= '"+expDate+"' and obj.expDate>='"+expDate+"')) and "+valueCondition;
		Session session = getSession();
		try{
			Query query = session.createQuery(sql);
			List list = query.list();
			if(list!=null && list.size()>0)
				bool = false;
		}
		catch (Exception e){
			bool = false;
			e.printStackTrace();
		}finally{
		}
		return bool;
	}

	public String getTableName(Class cls){
		SingleTableEntityPersister entityPersister=(SingleTableEntityPersister)this.getSessionFactory().getClassMetadata(cls);
		return entityPersister.getTableName();
	}
	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}
	public boolean logicDelete(Serializable[] ids) {
		// TODO Auto-generated method stub
		return false;
	}
	public boolean execHql(String sql) {
		// TODO Auto-generated method stub
		return false;
	}
}
